using System;
using System.Collections.Generic;
using System.Text;
using System.Threading;
using System.Globalization;
using System.ComponentModel;
using FreeLancer.HRB.Domains;
using FreeLancer.HRB.Services;
using System.Data;

namespace FreeLancer.HRB.Core
{
  /// <summary>
  /// A post is an entry on the blog - a blog post.
  /// </summary>
  [Serializable]
  public class Post : IComparable<Post>, IPublishable
  {
    #region Properties

    private Posts _data;
    /// <summary>
    /// Data of the Post
    /// </summary>
    public Posts Data
    {
      get { return _data; }
    }

    /// <summary>
    /// Gets or sets the Slug of the Page.
    /// A Slug is the relative URL used by the pages.
    /// </summary>
    public string Slug
    {
      get
      {
        if (string.IsNullOrEmpty(_data.Slug))
          return Utils.RemoveIllegalCharacters(Title);

        return _data.Slug;
      }
    }

    private List<Category> _categories = new List<Category>();

    private static object _syncRoot = new object();
    private static List<Post> _posts;
    /// <summary>
    /// A sorted collection of all posts without content in the blog.
    /// Sorted by date.
    /// </summary>
    public static List<Post> Posts
    {
      get
      {
        //if (_posts == null)
				//{
          lock (_syncRoot)
					{
            //if (_posts == null)
						//{
              _posts = FillSimplePosts();
              _posts.TrimExcess();
							//AddRelations();
						//}
					}
				//}

        return _posts;
      }
    }

    private static object _syncRootFull = new object();
    private static List<Post> _fullPosts;
    /// <summary>
    /// A sorted collection of all posts with content in the blog.
    /// Sorted by date.
    /// </summary>
    public static List<Post> FullPosts
    {
      get
      {
        if (_fullPosts == null)
        {
          //lock (_syncRootFull)
          //{
            if (_fullPosts == null)
            {
              _fullPosts = FillPosts();
              _fullPosts.TrimExcess();
              //AddRelations();
            }
          //}
        }

        return _posts;
      }
    }

    #endregion

    #region Constructor

    /// <summary>
    /// Construtor
    /// </summary>
    /// <param name="data">Post data</param>
    public Post(Posts data)
    {
      _data = data;
      Initialize();
    }

    private void Initialize()
    {
      if (_data.PostId != Guid.Empty)
      {
        PostCategoryService service = new PostCategoryService();
        CategoriesService cateService = new CategoriesService();

        TList<PostCategory> postCategories = service.GetByPostId(_data.PostId);
        foreach (PostCategory postCategory in postCategories)
        {
          FreeLancer.HRB.Domains.Categories categoryDomain = 
            cateService.GetByCategoryIdLanguageId(postCategory.CategoryId, postCategory.LanguageId);

          _categories.Add(new Category(categoryDomain));
        }
      }
    }

    #endregion

    #region IPublishable Members

    /// <summary>
    /// Gets the Title of the post.
    /// </summary>
    public string Title
    {
      get { return _data.Title; }
    }

    /// <summary>
    /// Gets the Content of the post.
    /// </summary>
    public string Content
    {
      get { return _data.PostContent; }
    }

    /// <summary>
    /// Gets when the Page was created.
    /// </summary>
    public DateTime DateCreated
    {
      get { return _data.DateCreated.Value; }
    }

    /// <summary>
    /// Gets when the Page was modified.
    /// </summary>
    public DateTime DateModified
    {
      get { return _data.DateModified.Value; }
    }

    /// <summary>
    /// Id of the Post
    /// </summary>
    public Guid Id
    {
      get { return _data.PostId; }
    }

    /// <summary>
    /// A relative-to-the-site-root path to the post.
    /// Only for in-site use.
    /// </summary>
    public string RelativeLink
    {
      get
      {
        string slug = Utils.RemoveIllegalCharacters(Slug) + WebAppSettings.Instance.FileExtension;

        if (WebAppSettings.Instance.TimeStampPostLinks)
          return Utils.RelativeWebRoot + "post/" + DateCreated.ToString("yyyy/MM/dd/", CultureInfo.InvariantCulture) + slug;

        return Utils.RelativeWebRoot + "post/" + slug;
      }
    }

    /// <summary>
    /// The absolute link to the post.
    /// </summary>
    public Uri AbsoluteLink
    {
      get { return Utils.ConvertToAbsolute(RelativeLink); }
    }

    /// <summary>
    /// Gets the Description of the post.
    /// </summary>
    public string Description
    {
      get { return _data.Description; }
    }

    /// <summary>
    /// Gets the Author of the post.
    /// </summary>
    public string Author
    {
      get { return _data.Author; }
    }

    /// <summary>
    /// Raises the Serving event
    /// </summary>
    public void OnServing(ServingEventArgs eventArgs)
    {
      if (Serving != null)
      {
        Serving(this, eventArgs);
      }
    }

    /// <summary>
    /// An List of categories.
    /// </summary>
    public List<Category> Categories
    {
      get { return _categories; }
    }

    /// <summary>
    /// Gets or sets whether or not the post is published.
    /// The getter also takes into account the publish date
    /// </summary>
    public bool IsPublished
    {
      get { return _data.IsPublished && DateCreated <= 
        DateTime.Now.AddHours(WebAppSettings.Instance.Timezone); }
    }

    /// <summary>
    /// Gets whether or not the post is visible or not.
    /// </summary>
    public bool IsVisible
    {
      get
      {
        if (Thread.CurrentPrincipal.Identity.IsAuthenticated || IsPublished)
          return true;

        return false;
      }
    }

    #endregion

    #region IComparable<Post> Members

    /// <summary>
    /// Compares the current object with another object of the same type.
    /// </summary>
    /// <param name="other">An object to compare with this object.</param>
    /// <returns>
    /// A 32-bit signed integer that indicates the relative order of the 
    /// objects being compared. The return value has the following meanings: 
    /// Value Meaning Less than zero This object is less than the other parameter.Zero 
    /// This object is equal to other. Greater than zero This object is greater than other.
    /// </returns>
    public int CompareTo(Post other)
    {
      return other.DateCreated.CompareTo(this.DateCreated);
    }

    #endregion

    #region Events

    /// <summary>
    /// Occurs before a new comment is added.
    /// </summary>
    public static event EventHandler<CancelEventArgs> AddingComment;
    /// <summary>
    /// Raises the event in a safe way
    /// </summary>
    protected virtual void OnAddingComment(Comment comment, CancelEventArgs e)
    {
      if (AddingComment != null)
      {
        AddingComment(comment, e);
      }
    }

    /// <summary>
    /// Occurs when a comment is added.
    /// </summary>
    public static event EventHandler<EventArgs> CommentAdded;
    /// <summary>
    /// Raises the event in a safe way
    /// </summary>
    protected virtual void OnCommentAdded(Comment comment)
    {
      if (CommentAdded != null)
      {
        CommentAdded(comment, new EventArgs());
      }
    }

    /// <summary>
    /// Occurs before comment is removed.
    /// </summary>
    public static event EventHandler<CancelEventArgs> RemovingComment;
    /// <summary>
    /// Raises the event in a safe way
    /// </summary>
    protected virtual void OnRemovingComment(Comment comment, CancelEventArgs e)
    {
      if (RemovingComment != null)
      {
        RemovingComment(comment, e);
      }
    }

    /// <summary>
    /// Occurs when a comment has been removed.
    /// </summary>
    public static event EventHandler<EventArgs> CommentRemoved;
    /// <summary>
    /// Raises the event in a safe way
    /// </summary>
    protected virtual void OnCommentRemoved(Comment comment)
    {
      if (CommentRemoved != null)
      {
        CommentRemoved(comment, new EventArgs());
      }
    }

    /// <summary>
    /// Occurs when a visitor rates the post.
    /// </summary>
    public static event EventHandler<EventArgs> Rated;
    /// <summary>
    /// Raises the event in a safe way
    /// </summary>
    protected virtual void OnRated(Post post)
    {
      if (Rated != null)
      {
        Rated(post, new EventArgs());
      }
    }

    /// <summary>
    /// Occurs when the post is being served to the output stream.
    /// </summary>
    public static event EventHandler<ServingEventArgs> Serving;
    /// <summary>
    /// Raises the event in a safe way
    /// </summary>
    public static void OnServing(Post post, ServingEventArgs arg)
    {
      if (Serving != null)
      {
        Serving(post, arg);
      }
    }

    #endregion

    #region Helpers

    private static List<Post> FillSimplePosts()
    {
      List<Post> posts = new List<Post>();
      PostsService service = GlobalCache.PostServiceInstance;

      DataSet dtsPost = service.GetAllSimplePosts();

      if (dtsPost.Tables.Count > 0)
      {
        DataTable dtbPost = dtsPost.Tables[0];

        foreach (DataRow row in dtbPost.Rows)
        {
          Posts postDomain = new Posts();
          if (row["Address"] != DBNull.Value)
            postDomain.Address = (string)row["Address"];
          if (row["AttachedPath"] != DBNull.Value)
            postDomain.AttachedPath = (string)row["AttachedPath"];
          if (row["Author"] != DBNull.Value)
            postDomain.Author = (string)row["Author"];
          if (row["DateCreated"] != DBNull.Value)
            postDomain.DateCreated = (DateTime)row["DateCreated"];
          if (row["DateModified"] != DBNull.Value)
            postDomain.DateModified = (DateTime)row["DateModified"];
          if (row["Description"] != DBNull.Value)
            postDomain.Description = (string)row["Description"];
          if (row["Email"] != DBNull.Value)
            postDomain.Email = (string)row["Email"];
          if (row["ImagePath"] != DBNull.Value)
            postDomain.ImagePath = (string)row["ImagePath"];
          if (row["IsCommentAllowed"] != DBNull.Value)
            postDomain.IsCommentAllowed = (bool)row["IsCommentAllowed"];
          if (row["IsPublished"] != DBNull.Value)
            postDomain.IsPublished = (bool)row["IsPublished"];
          if (row["Phone"] != DBNull.Value)
            postDomain.Phone = (string)row["Phone"];
          if (row["PostID"] != DBNull.Value)
            postDomain.PostId = new Guid(row["PostID"].ToString());
          if (row["Slug"] != DBNull.Value)
            postDomain.Slug = (string)row["Slug"];
          if (row["Title"] != DBNull.Value)
            postDomain.Title = (string)row["Title"];

          posts.Add(new Post(postDomain));
        }
      }

      return posts;
    }

    private static List<Post> FillPosts()
    {
      List<Post> posts = new List<Post>();
      PostsService service = GlobalCache.PostServiceInstance;

      TList<FreeLancer.HRB.Domains.Posts> postDomains = service.GetAll();
      foreach (Posts postDomain in postDomains)
      {
        posts.Add(new Post(postDomain));
      }

      return posts;
    }

    #endregion
  }
}
